<!doctype html><html lang=en-us><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=description content="基本信息  Dockerfile 为 Docker 提供镜像构建命令及描述。 Docker 书写思想：  自动化，无交互 顺序相关 清理 易读    基础语法  // 注释 INSTRUCTION arguments 指令格式，一般指令名大写  指令 FROM 指定基础镜像，必须是第一句有效指令。
FROM&amp;lt;imagesName:tag&amp;gt;多个 FROM 指令使用最后一个。
MAINTAINER 设置维护者信息。
MAINTAINERName &amp;lt;Email&amp;gt;RUN 运行指定命令。
 shell 格式  RUN echo HelloWorld exec 格式（不启动 shell）  RUN [&amp;#34;prog&amp;#34;, &amp;#34;arg1&amp;#34;, &amp;#34;arg2&amp;#34;]ENV 设置镜像的环境变量。
ENV &amp;lt;key&amp;gt; &amp;lt;value&amp;gt;COPY 将本地文件或文件夹复制到镜像指定路径下。
COPY /local/path/file /images/path/fileADD 可从本地或网上获取，存储到镜像指定路径下，也可对文件自动解包。
ADD file /images/path/fileADD latest.tar.gz /var/www/ 相同复制命令下，ADD 构建的镜像比 COPY 构建的镜像大 不能对构建目录或上下文之外的文件进行 ADD 操作：不能使用 ."><title>Dockerfile</title><link rel=canonical href=https://stardustdl.gitee.io/posts/tools/proglang-dockerfile/><link rel=stylesheet href=/scss/style.min.css><meta property="og:title" content="Dockerfile"><meta property="og:description" content="基本信息  Dockerfile 为 Docker 提供镜像构建命令及描述。 Docker 书写思想：  自动化，无交互 顺序相关 清理 易读    基础语法  // 注释 INSTRUCTION arguments 指令格式，一般指令名大写  指令 FROM 指定基础镜像，必须是第一句有效指令。
FROM&amp;lt;imagesName:tag&amp;gt;多个 FROM 指令使用最后一个。
MAINTAINER 设置维护者信息。
MAINTAINERName &amp;lt;Email&amp;gt;RUN 运行指定命令。
 shell 格式  RUN echo HelloWorld exec 格式（不启动 shell）  RUN [&amp;#34;prog&amp;#34;, &amp;#34;arg1&amp;#34;, &amp;#34;arg2&amp;#34;]ENV 设置镜像的环境变量。
ENV &amp;lt;key&amp;gt; &amp;lt;value&amp;gt;COPY 将本地文件或文件夹复制到镜像指定路径下。
COPY /local/path/file /images/path/fileADD 可从本地或网上获取，存储到镜像指定路径下，也可对文件自动解包。
ADD file /images/path/fileADD latest.tar.gz /var/www/ 相同复制命令下，ADD 构建的镜像比 COPY 构建的镜像大 不能对构建目录或上下文之外的文件进行 ADD 操作：不能使用 ."><meta property="og:url" content="https://stardustdl.gitee.io/posts/tools/proglang-dockerfile/"><meta property="og:site_name" content="StardustDL's Blog"><meta property="og:type" content="article"><meta property="article:section" content="Posts"><meta property="article:tag" content="编程语言"><meta property="article:published_time" content="2018-11-12T19:37:36+08:00"><meta property="article:modified_time" content="2018-11-12T19:37:36+08:00"><meta name=twitter:title content="Dockerfile"><meta name=twitter:description content="基本信息  Dockerfile 为 Docker 提供镜像构建命令及描述。 Docker 书写思想：  自动化，无交互 顺序相关 清理 易读    基础语法  // 注释 INSTRUCTION arguments 指令格式，一般指令名大写  指令 FROM 指定基础镜像，必须是第一句有效指令。
FROM&amp;lt;imagesName:tag&amp;gt;多个 FROM 指令使用最后一个。
MAINTAINER 设置维护者信息。
MAINTAINERName &amp;lt;Email&amp;gt;RUN 运行指定命令。
 shell 格式  RUN echo HelloWorld exec 格式（不启动 shell）  RUN [&amp;#34;prog&amp;#34;, &amp;#34;arg1&amp;#34;, &amp;#34;arg2&amp;#34;]ENV 设置镜像的环境变量。
ENV &amp;lt;key&amp;gt; &amp;lt;value&amp;gt;COPY 将本地文件或文件夹复制到镜像指定路径下。
COPY /local/path/file /images/path/fileADD 可从本地或网上获取，存储到镜像指定路径下，也可对文件自动解包。
ADD file /images/path/fileADD latest.tar.gz /var/www/ 相同复制命令下，ADD 构建的镜像比 COPY 构建的镜像大 不能对构建目录或上下文之外的文件进行 ADD 操作：不能使用 ."><link rel="shortcut icon" href=/favicon.png><script type=application/javascript>var doNotTrack=!1;doNotTrack||(function(a,e,f,g,b,c,d){a.GoogleAnalyticsObject=b,a[b]=a[b]||function(){(a[b].q=a[b].q||[]).push(arguments)},a[b].l=1*new Date,c=e.createElement(f),d=e.getElementsByTagName(f)[0],c.async=1,c.src=g,d.parentNode.insertBefore(c,d)}(window,document,'script','https://www.google-analytics.com/analytics.js','ga'),ga('create','UA-111573521-1','auto'),ga('send','pageview'))</script></head><body class="article-page has-toc"><script>(function(){const a='StackColorScheme';localStorage.getItem(a)||localStorage.setItem(a,"auto")})()</script><script>(function(){const b='StackColorScheme',a=localStorage.getItem(b),c=window.matchMedia('(prefers-color-scheme: dark)').matches===!0;a=='dark'||a==='auto'&&c?document.documentElement.dataset.scheme='dark':document.documentElement.dataset.scheme='light'})()</script><div class="container main-container flex
extended"><div id=article-toolbar><a href=/ class=back-home><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevron-left" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentcolor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z"/><polyline points="15 6 9 12 15 18"/></svg><span>Back</span></a></div><main class="main full-width"><article class=main-article><header class=article-header><div class=article-details><header class=article-category><a href=/categories/tools/>Tools</a></header><h2 class=article-title><a href=/posts/tools/proglang-dockerfile/>Dockerfile</a></h2><footer class=article-time><div><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-calendar-time" width="56" height="56" viewBox="0 0 24 24" stroke-width="2" stroke="currentcolor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z"/><path d="M11.795 21H5a2 2 0 01-2-2V7a2 2 0 012-2h12a2 2 0 012 2v4"/><circle cx="18" cy="18" r="4"/><path d="M15 3v4"/><path d="M7 3v4"/><path d="M3 11h16"/><path d="M18 16.496V18l1 1"/></svg><time class=article-time--published>Nov 12, 2018</time></div><div><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-clock" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentcolor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z"/><circle cx="12" cy="12" r="9"/><polyline points="12 7 12 12 15 15"/></svg><time class=article-time--reading>1 minute read</time></div></footer></div></header><section class=article-content><h1 id=基本信息>基本信息</h1><ul><li>Dockerfile 为 Docker 提供镜像构建命令及描述。</li><li>Docker 书写思想：<ul><li>自动化，无交互</li><li>顺序相关</li><li>清理</li><li>易读</li></ul></li></ul><h1 id=基础语法>基础语法</h1><ul><li><code>//</code> 注释</li><li><code>INSTRUCTION arguments</code> 指令格式，一般指令名大写</li></ul><h1 id=指令>指令</h1><h2 id=from>FROM</h2><p>指定基础镜像，必须是第一句有效指令。</p><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=k>FROM</span><span class=s> &lt;imagesName:tag&gt;</span><span class=err>
</span></code></pre></div><p>多个 <code>FROM</code> 指令使用最后一个。</p><h2 id=maintainer>MAINTAINER</h2><p>设置维护者信息。</p><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=k>MAINTAINER</span><span class=s> Name &lt;Email&gt;</span><span class=err>
</span></code></pre></div><h3 id=run>RUN</h3><p>运行指定命令。</p><ul><li>shell 格式</li></ul><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=k>RUN</span> <span class=nb>echo</span> HelloWorld<span class=err>
</span></code></pre></div><ul><li>exec 格式（不启动 shell）</li></ul><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=k>RUN</span> <span class=o>[</span><span class=s2>&#34;prog&#34;</span>, <span class=s2>&#34;arg1&#34;</span>, <span class=s2>&#34;arg2&#34;</span><span class=o>]</span><span class=err>
</span></code></pre></div><h3 id=env>ENV</h3><p>设置镜像的环境变量。</p><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=k>ENV</span> &lt;key&gt; &lt;value&gt;<span class=err>
</span></code></pre></div><h3 id=copy>COPY</h3><p>将本地文件或文件夹复制到镜像指定路径下。</p><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=k>COPY</span> /local/path/file /images/path/file<span class=err>
</span></code></pre></div><h3 id=add>ADD</h3><p>可从本地或网上获取，存储到镜像指定路径下，也可对文件自动解包。</p><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=k>ADD</span> file /images/path/file<span class=err>
</span><span class=err></span><span class=k>ADD</span> latest.tar.gz /var/www/<span class=err>
</span></code></pre></div><ul><li>相同复制命令下，ADD 构建的镜像比 COPY 构建的镜像大</li><li>不能对构建目录或上下文之外的文件进行 ADD 操作：不能使用 <code>../path</code></li><li>会自动创建目的位置</li><li>会使得构建缓存无效</li></ul><h3 id=expose>EXPOSE</h3><p>指定暴露端口。</p><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=k>EXPOSE</span><span class=s> &lt;port&gt; [&lt;port&gt;...]</span><span class=err>
</span></code></pre></div><h3 id=cmd>CMD</h3><p>设置镜像启动命令。只有最后一个 CMD 指令有效。</p><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=k>CMD</span> <span class=p>[</span><span class=s2>&#34;echo&#34;</span><span class=p>,</span> <span class=s2>&#34;Hello World&#34;</span><span class=p>]</span><span class=err>
</span></code></pre></div><h3 id=entrypoint>ENTRYPOINT</h3><p>设置入口点。</p><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=k>ENTRYPOINT</span> <span class=p>[</span><span class=s2>&#34;echo&#34;</span><span class=p>]</span><span class=err>
</span></code></pre></div><h3 id=volume>VOLUME</h3><p>设置数据卷。</p><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=k>VOLUME</span> <span class=p>[</span><span class=s2>&#34;/data&#34;</span><span class=p>,</span> <span class=s2>&#34;/data2&#34;</span><span class=p>]</span><span class=err>
</span></code></pre></div><h3 id=user>USER</h3><p>设置构建用户。指定的用户需要在 USER 指令前创建。</p><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=k>USER</span><span class=s> user</span><span class=err>
</span><span class=err></span><span class=k>USER</span><span class=s> user:group</span><span class=err>
</span><span class=err></span><span class=k>USER</span><span class=s> uid:gid</span><span class=err>
</span></code></pre></div><h3 id=workdir>WORKDIR</h3><p>设置 RUN,CMD,ENTRYPOINT 工作目录。</p><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=k>WORKDIR</span><span class=s> /path/workdir</span><span class=err>
</span></code></pre></div><h3 id=onbuild>ONBUILD</h3><p>用于子镜像的二次构建中执行的 Dockerfile 指令。</p><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=k>ONBUILD</span> <span class=k>RUN</span> <span class=nb>echo</span> <span class=s2>&#34;Hello World&#34;</span><span class=err>
</span></code></pre></div><h3 id=label>LABEL</h3><p>添加元数据到镜像。尽量使用一个 LABEL 标签，减少构建 layer 数量。</p><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=k>LABEL</span> multi.label1<span class=o>=</span><span class=s2>&#34;value1&#34;</span> multi.label2<span class=o>=</span><span class=s2>&#34;value2&#34;</span><span class=err>
</span></code></pre></div><h3 id=arg>ARG</h3><p>设置构建变量。</p><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=k>ARG</span> &lt;key&gt; &lt;value&gt;<span class=err>
</span></code></pre></div><h3 id=stopsignal>STOPSIGNAL</h3><p>指定运行 <code>docker stop</code> 时，向容器发送的信号。</p><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=k>STOPSIGNAL</span><span class=s> SIGKILL</span><span class=err>
</span></code></pre></div><h3 id=healthcheck>HEALTHCHECK</h3><p>检查容器状态。</p><p>参数有：</p><ul><li><code>--interval</code> 容器启动多长时间后开始检查</li><li><code>--timeout</code> 设置超时时间，若超时，则认为容器异常</li><li><code>--retried</code> 设置重试次数</li></ul><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=err>HEALTHCHECK</span> <span class=o>[</span>OPTIONS<span class=o>]</span> CMD command<span class=err>
</span></code></pre></div><h3 id=shell>SHELL</h3><p>指示更换 shell 环境。</p><div class=highlight><pre class=chroma><code class=language-Dockerfile data-lang=Dockerfile><span class=k>SHELL</span> <span class=p>[</span><span class=s2>&#34;powershell&#34;</span><span class=p>,</span> <span class=s2>&#34;-command&#34;</span><span class=p>]</span><span class=err>
</span></code></pre></div><h1 id=参考资料>参考资料</h1><ul><li>《Docker 从入门到实战》 黄靖钧 机械工业出版社</li></ul></section><footer class=article-footer><section class=article-tags><a href=/tags/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/>编程语言</a></section><section class=article-copyright><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-copyright" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentcolor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z"/><circle cx="12" cy="12" r="9"/><path d="M14.5 9a3.5 4 0 100 6"/></svg><span>Licensed under CC BY-NC-SA 4.0</span></section></footer><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/katex@0.13.13/dist/katex.min.css integrity=sha384-RZU/ijkSsFbcmivfdRBQDtwuwVqK7GMOw6IMvKyeWL2K5UAlyp6WonmB8m7Jd0Hn crossorigin=anonymous><script src=https://cdn.jsdelivr.net/npm/katex@0.13.13/dist/katex.min.js integrity=sha384-pK1WpvzWVBQiP0/GjnvRxV4mOb0oxFuyRxJlk6vVw146n3egcN5C925NCP7a7BY8 crossorigin=anonymous defer></script><script src=https://cdn.jsdelivr.net/npm/katex@0.13.13/dist/contrib/auto-render.min.js integrity=sha384-vZTG03m+2yp6N6BNi5iM4rW4oIwk5DfcNdFfxkk9ZWpDriOkXX8voJBFrAO7MpVl crossorigin=anonymous defer></script><script>window.addEventListener("DOMContentLoaded",()=>{renderMathInElement(document.querySelector(`.article-content`),{delimiters:[{left:"$$",right:"$$",display:!0},{left:"$",right:"$",display:!1},{left:"\\(",right:"\\)",display:!1},{left:"\\[",right:"\\]",display:!0}]})})</script></article><aside class=related-contents--wrapper><h2 class=section-title>Related contents</h2><div class=related-contents><div class="flex article-list--tile"><article class=has-image><a href=/posts/tools/proglang-yaml/><div class=article-image><img src=https://raw.githubusercontent.com/github/explore/80688e429a7d4ef2fca1e82350fe8e3517d3494d/topics/yaml/yaml.png loading=lazy data-key data-hash=https://raw.githubusercontent.com/github/explore/80688e429a7d4ef2fca1e82350fe8e3517d3494d/topics/yaml/yaml.png></div><div class=article-details><h2 class=article-title>YAML Ain't Markup Language</h2></div></a></article><article><a href=/posts/tools/proglang-makefile/><div class=article-details><h2 class=article-title>Makefile</h2></div></a></article><article><a href=/posts/tools/proglang-verilog/><div class=article-details><h2 class=article-title>Verilog HDL</h2></div></a></article><article class=has-image><a href=/posts/tools/proglang-css/><div class=article-image><img src=https://raw.githubusercontent.com/github/explore/80688e429a7d4ef2fca1e82350fe8e3517d3494d/topics/css/css.png loading=lazy data-key data-hash=https://raw.githubusercontent.com/github/explore/80688e429a7d4ef2fca1e82350fe8e3517d3494d/topics/css/css.png></div><div class=article-details><h2 class=article-title>Cascading Style Sheets</h2></div></a></article><article class=has-image><a href=/posts/tools/proglang-html/><div class=article-image><img src=https://raw.githubusercontent.com/github/explore/80688e429a7d4ef2fca1e82350fe8e3517d3494d/topics/html/html.png loading=lazy data-key data-hash=https://raw.githubusercontent.com/github/explore/80688e429a7d4ef2fca1e82350fe8e3517d3494d/topics/html/html.png></div><div class=article-details><h2 class=article-title>Hyper Text Markup Language</h2></div></a></article></div></div></aside><script src=https://utteranc.es/client.js repo=StardustDL/stardustdl.github.io issue-term=pathname label=comment crossorigin=anonymous async></script><style>.utterances{max-width:unset}</style><script>function setUtterancesTheme(b){let a=document.querySelector('.utterances iframe');a&&a.contentWindow.postMessage({type:'set-theme',theme:`github-${b}`},'https://utteranc.es')}addEventListener('message',a=>{if(a.origin!=='https://utteranc.es')return;setUtterancesTheme(document.documentElement.dataset.scheme)}),window.addEventListener('onColorSchemeChange',a=>{setUtterancesTheme(a.detail)})</script><footer class=site-footer><section class=copyright>&copy;
2017 -
2021 StardustDL's Blog</section><section class=powerby><a style=color:gray href=http://www.beian.miit.gov.cn>冀ICP备19021004号</a><br>Built with <a href=https://gohugo.io/ target=_blank rel=noopener>Hugo</a><br>Theme <b><a href=https://github.com/CaiJimmy/hugo-theme-stack target=_blank rel=noopener data-version=3.5.0>Stack</a></b> designed by <a href=https://jimmycai.com target=_blank rel=noopener>Jimmy</a></section></footer><div class=pswp tabindex=-1 role=dialog aria-hidden=true><div class=pswp__bg></div><div class=pswp__scroll-wrap><div class=pswp__container><div class=pswp__item></div><div class=pswp__item></div><div class=pswp__item></div></div><div class="pswp__ui pswp__ui--hidden"><div class=pswp__top-bar><div class=pswp__counter></div><button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
<button class="pswp__button pswp__button--share" title=Share></button>
<button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
<button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button><div class=pswp__preloader><div class=pswp__preloader__icn><div class=pswp__preloader__cut><div class=pswp__preloader__donut></div></div></div></div></div><div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap"><div class=pswp__share-tooltip></div></div><button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)"></button>
<button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)"></button><div class=pswp__caption><div class=pswp__caption__center></div></div></div></div></div><script src=https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.js integrity="sha256-ePwmChbbvXbsO02lbM3HoHbSHTHFAeChekF1xKJdleo=" crossorigin=anonymous defer></script><script src=https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe-ui-default.min.js integrity="sha256-UKkzOn/w1mBxRmLLGrSeyB4e1xbrp4xylgAWb3M42pU=" crossorigin=anonymous defer></script><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/default-skin/default-skin.css integrity="sha256-c0uckgykQ9v5k+IqViZOZKc47Jn7KQil4/MP3ySA3F8=" crossorigin=anonymous><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.css integrity="sha256-SBLU4vv6CA6lHsZ1XyTdhyjJxCjPif/TRkjnsyGAGnE=" crossorigin=anonymous></main><aside class="sidebar right-sidebar sticky"><section class="widget archives"><div class=widget-icon><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-hash" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentcolor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z"/><line x1="5" y1="9" x2="19" y2="9"/><line x1="5" y1="15" x2="19" y2="15"/><line x1="11" y1="4" x2="7" y2="20"/><line x1="17" y1="4" x2="13" y2="20"/></svg></div><h2 class="widget-title section-title">Table of contents</h2><div class=widget--toc><nav id=TableOfContents><ol><li><a href=#基本信息>基本信息</a></li><li><a href=#基础语法>基础语法</a></li><li><a href=#指令>指令</a><ol><li><a href=#from>FROM</a></li><li><a href=#maintainer>MAINTAINER</a><ol><li><a href=#run>RUN</a></li><li><a href=#env>ENV</a></li><li><a href=#copy>COPY</a></li><li><a href=#add>ADD</a></li><li><a href=#expose>EXPOSE</a></li><li><a href=#cmd>CMD</a></li><li><a href=#entrypoint>ENTRYPOINT</a></li><li><a href=#volume>VOLUME</a></li><li><a href=#user>USER</a></li><li><a href=#workdir>WORKDIR</a></li><li><a href=#onbuild>ONBUILD</a></li><li><a href=#label>LABEL</a></li><li><a href=#arg>ARG</a></li><li><a href=#stopsignal>STOPSIGNAL</a></li><li><a href=#healthcheck>HEALTHCHECK</a></li><li><a href=#shell>SHELL</a></li></ol></li></ol></li><li><a href=#参考资料>参考资料</a></li></ol></nav></div></section></aside></div><script src=https://cdn.jsdelivr.net/npm/node-vibrant@3.1.5/dist/vibrant.min.js integrity="sha256-5NovOZc4iwiAWTYIFiIM7DxKUXKWvpVEuMEPLzcm5/g=" crossorigin=anonymous defer></script><script type=text/javascript src=/ts/main.js defer></script><script>(function(){const a=document.createElement('link');a.href="https://fonts.googleapis.com/css2?family=Lato:wght@300;400;700&display=swap",a.type="text/css",a.rel="stylesheet",document.head.appendChild(a)})()</script></body></html>